home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / develop™ Technical Journal / develop Issue 25 code / FontToPict (Space Hack GX) / Exceptions.h next >
Encoding:
C/C++ Source or Header  |  1995-10-07  |  21.9 KB  |  841 lines  |  [TEXT/MPS ]

  1.  
  2. /**************************************************************************************
  3.  
  4. FILENAME
  5.     Exceptions.h
  6.     
  7. DESCRIPTION
  8.     A collection of routines to handle assertions and exceptions.
  9.  
  10. COPYRIGHT
  11.     Copyright © Apple Computer, Inc. 1989-1993
  12.     All rights reserved.
  13.  
  14. ROUTINES
  15.     EXTERNALS
  16.         dprintf
  17.  
  18. MACROS
  19.     EXTERNALS
  20.         SetExceptionOption - resumeLabelsOn / resumeLabelsOff
  21.         check
  22.         ncheck
  23.         check_action
  24.         ncheck_action
  25.         require
  26.         nrequire
  27.         require_action
  28.         nrequire_action
  29.         retry
  30.         resume
  31.  
  32.         
  33. NOTE
  34.     To keep code size down, use these routines and macros with the C compiler option
  35.     -b2 or -b3. This will eliminate duplicate strings.
  36. NOTE
  37.     For more information on exception handling please refer to the book "Object-
  38.     oriented Software Construction" by Bertrand Meyer, Prentice Hall International.
  39.     Also, read the _develop_ article on Exception Handling by Sean Parent.
  40.  
  41. **************************************************************************************/
  42.  
  43. #ifndef __EXCEPTIONS__
  44. #define __EXCEPTIONS__
  45.  
  46. /**************************************************************************************
  47.  
  48. INCLUDES
  49.  
  50. **************************************************************************************/
  51.  
  52. #ifndef        __TYPES__
  53. #include    <Types.h>
  54. #endif
  55.  
  56. /*<FF>*/
  57. /**************************************************************************************
  58.  
  59. CONSTANTS AND CONTROL
  60.  
  61. **************************************************************************************/
  62.  
  63. #define DEBUGOFF        0
  64. #define DEBUGWARN        1
  65. #define DEBUGON            2
  66. #define DEBUGFULL        3
  67.  
  68. #ifndef DEBUGLEVEL
  69.     #define DEBUGLEVEL DEBUGOFF
  70. #endif     // DEBUGLEVEL
  71.  
  72. /*
  73.     Declare a prototype that is used to ensure proper use of semicolons.
  74. */
  75.  
  76. void PlaceHolder(void);
  77.  
  78. /*
  79.     These macros are used to control the insertion of the resume labels. If off
  80.     then you can have multible requires sharing the same label but cannot resume.
  81. */
  82.  
  83. #define resumeLabelsOn(exception) resume_ ## exception:
  84. #define resumeLabelsOff(exception)
  85.  
  86. /*
  87.     When using SetExceptionOption do not put a ; or anything other than a comment
  88.     after the macro.
  89. */
  90.  
  91. /* We disable resume labels, and the SetExceptionOption macro because they are
  92.     not ANSI C happy */
  93. #define resumeLabel(exception) 
  94. #define SetExceptionOption(option)
  95.  
  96. /*
  97.     trace and notrace are used for the traceOption for dprintf. If trace is used then
  98.     the actual behavior cn be controled from Macsbug. The macros in Macsbug are traceGo
  99.     and traceBreak. traceGo is the default and execution will continue after the break.
  100.     If traceBreak is used then execution will halt.
  101. */
  102.  
  103. #define trace    "\p;dprintf;doTrace"
  104. #define    notrace    "\p;dprintf;mnop"
  105.  
  106. /*
  107.     traceon and debugon are used to test for options. For example:
  108.     
  109.     #if traceon
  110.     dprintf(trace, "Foo Happened %d", 10);
  111.     #endif
  112.     
  113.     #if debugon
  114.     dprintf(notrace, "Foo Happened %d", 10);
  115.     #endif
  116. */
  117.  
  118.  
  119. #define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON))
  120. #define debugon (DEBUGLEVEL > DEBUGWARN)
  121.  
  122. /*<FF>*/
  123. /**************************************************************************************
  124.  
  125. ROUTINE
  126.     dprintf
  127.  
  128. DESCRIPTION
  129.     dprintf is used like printf only the information is displayed in MacsBug.
  130.     traceOption is used to specify whether the execution should continue after the
  131.     break or not. Of the standard printf convertion characters only "n" is not
  132.     supported. In addition to the standard characters, the following are defined:
  133.     
  134.         b    Boolean. Outputs either true or false.
  135.         l    Point. Used like the d option. (the l is for location.)
  136.         L    point*. Used like the f option. (the L is for Location.)
  137.         F    Fixed point number. Used like the f option.
  138.         T    Fract number. Used like the f option.
  139.         r    Rect*. Displays the rect with each piece seperated by ", ". Used like the
  140.             d option.
  141.         R    rectangle*. Similar to r but for fixed point rectangles. Used like the
  142.             f option.
  143.         M    mapping. Displays the mapping seperated by ", " and "\n". The third column
  144.             is displayed as fract. Used like the f option.
  145.     
  146.     dprintf requires that the MacsBug dcmd dprintf is present.
  147.     
  148. EXAMPLE
  149.     The code:
  150.     
  151.         dprintf(notrace, "This is a Fract: %.8T", 0x70000000);
  152.     
  153.     Will display:
  154.     
  155.         This is a Fract: 1.75000000
  156.     
  157.     See the MPW C Reference for more information on printf.
  158.  
  159. **************************************************************************************/
  160. void dprintf(StringPtr traceOption, char theFormat[], ...)
  161. TWOWORDINLINE(0xABFF,0x594F);
  162. /*<FF>*/
  163. /**************************************************************************************
  164.  
  165. ROUTINE check_dprintf
  166.  
  167. DESCRIPTION
  168.     if assertion is non-zero then assertion is returned. Otherwise the dprintf is
  169.     invoked and zero is returned.
  170.     
  171. Echo "                                                        ∂n∂
  172.     PROC                                                    ∂n∂
  173.     MOVE.L    (SP)+,D0        ; Pop value into D0                ∂n∂
  174.     BNE.S    @1                ; If !0 then branch                ∂n∂
  175.     DC.W    $ABFF            ; DebugStr                        ∂n∂
  176.     SUBQ    #4,SP            ; Fix stack for debugStr        ∂n∂
  177.     CLR.W    D0                ; result is zero                ∂n∂
  178. @1    SUBQ    #4,SP            ; Fix stack for pop                ∂n∂
  179.     ENDPROC                                                    ∂n∂
  180.     END                                                        ∂n∂
  181. " | Asm -l
  182.     
  183. **************************************************************************************/
  184.     
  185. void* check_dprintf(void* assertion, StringPtr traceOption, char theFormat[], ...)
  186. SIXWORDINLINE(0x201F, 0x6606, 0xABFF, 0x594F, 0x4240, 0x594F);
  187.     
  188. /*<FF>*/
  189. /**************************************************************************************
  190.  
  191. ROUTINE checkpos_dprintf
  192.  
  193. DESCRIPTION
  194.     if assertion is non-zero then assertion is returned. Otherwise the dprintf is
  195.     invoked and zero is returned.
  196.     
  197. Echo "                                                        ∂n∂
  198.     PROC                                                    ∂n∂
  199.     MOVE.L    (SP)+,D0        ; Pop value into D0                ∂n∂
  200.     BGE.S    @1                ; If >= 0 then branch            ∂n∂
  201.     DC.W    $ABFF            ; DebugStr                        ∂n∂
  202.     SUBQ    #4,SP            ; Fix stack for debugStr        ∂n∂
  203.     CLR.W    D0                ; result is zero                ∂n∂
  204. @1    SUBQ    #4,SP            ; Fix stack for pop                ∂n∂
  205.     ENDPROC                                                    ∂n∂
  206.     END                                                        ∂n∂
  207. " | Asm -l
  208.     
  209. **************************************************************************************/
  210.     
  211. void* checkpos_dprintf(void* assertion, StringPtr traceOption, char theFormat[], ...)
  212. SIXWORDINLINE(0x201F, 0x6C06, 0xABFF, 0x594F, 0x4240, 0x594F);
  213.  
  214. /*<FF>*/
  215. /**************************************************************************************
  216.  
  217. MACRO
  218.     check
  219.  
  220. DESCRIPTION
  221.     If DEBUGON or DEBUGFULL are defined then check will test the assertion and if it
  222.     failes break to the Debugger and print the assertion. If DEBUGON or DEBUGFULL are
  223.     not defined then check does nothing.
  224.  
  225. EXAMPLE
  226.     check is very useful for testing preconditions. In the below example DoStuff is
  227.     defined to take a handle to some object. It is a precondition of DoStuff that the
  228.     handle must not be nil (and therefore is the callers resposibility to ensure that
  229.     it is not.
  230.  
  231.         void DoStuff(Handle h)
  232.         {
  233.             check(h);
  234.             (FooType)(*h)->fooField = 0;
  235.         } 
  236.     
  237.     Durring testing, however, if DEBUGFULL where defined and a caller did not live up
  238.     to the contract by passing in a nil handle then a break would occure with the
  239.     following:
  240.     
  241.         Assertion "h" Failed
  242.         File: FooDisk:FooFile
  243.         Line: 3
  244.  
  245. **************************************************************************************/
  246.  
  247. #if DEBUGLEVEL==DEBUGON
  248.  
  249. #define check(assertion)                                                \
  250.     if (true) {                                                            \
  251.         if (assertion) ;                                                \
  252.         else {                                                            \
  253.             dprintf(notrace, "Assertion \"%s\" Failed",    #assertion);    \
  254.         }                                                                \
  255.     } else PlaceHolder()
  256.  
  257. #elif DEBUGLEVEL==DEBUGFULL
  258.  
  259. #define check(assertion)                                                \
  260.     if (true) {                                                            \
  261.         if (assertion) ;                                                \
  262.         else {                                                            \
  263.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  264.                                 "File: %s\n"                            \
  265.                                 "Line: %d",                                \
  266.                 #assertion, __FILE__, __LINE__);                        \
  267.         }                                                                \
  268.     } else PlaceHolder()
  269.  
  270. #else
  271.  
  272. #define check(assertion)
  273.  
  274. #endif
  275.  
  276. /*<FF>*/
  277. /**************************************************************************************
  278.  
  279. MACRO
  280.     ncheck
  281.  
  282. DESCRIPTION
  283.     ncheck is the same as check only it requires that the assertion is false.
  284.  
  285. EXAMPLE
  286.     ncheck is very useful for testing results when no recovery can be taken even if
  287.     the action fails. This is most commen durring clean up.
  288.  
  289.         void DisposeStuff(shape theShape)
  290.         {
  291.             DisposeShape(theShape);
  292.             ncheck(GetError());
  293.         } 
  294.     
  295.     If DEBUGFULL where defined and for some reason the dealocation failed then the
  296.     following would be reported:
  297.     
  298.         Assertion "!(GetError() [= -108])" Failed
  299.         File: FooDisk:FooFile
  300.         Line: 3
  301.  
  302. **************************************************************************************/
  303.  
  304. #if    DEBUGLEVEL==DEBUGON
  305.  
  306. #define ncheck(assertion)                                                \
  307.     if (true) {                                                            \
  308.         void*    __privateAssertion    = (void*)(assertion);                \
  309.                                                                         \
  310.         if (__privateAssertion) {                                        \
  311.             dprintf(notrace, "Assertion \"!(%s [= 0x%08X])\" Failed",    \
  312.                 #assertion, __privateAssertion);                        \
  313.         }                                                                \
  314.     } else PlaceHolder()
  315.  
  316. #elif DEBUGLEVEL==DEBUGFULL
  317.  
  318. #define ncheck(assertion)                                                    \
  319.     if (true) {                                                                \
  320.         void*    __privateAssertion    = (void*)(assertion);                    \
  321.                                                                             \
  322.         if (__privateAssertion) {                                            \
  323.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"    \
  324.                                 "File: %s\n"                                \
  325.                                 "Line: %d",                                    \
  326.             #assertion, __privateAssertion, __FILE__, __LINE__);            \
  327.         }                                                                    \
  328.     } else PlaceHolder()
  329.  
  330. #else
  331.  
  332. #define ncheck(assertion)
  333.  
  334. #endif
  335.  
  336. /*<FF>*/
  337. /**************************************************************************************
  338.  
  339. MACRO
  340.     check_action
  341.  
  342. DESCRIPTION
  343.     If DEBUGON or DEBUGFULL are defined then check_action will test the assertion and
  344.     if it failes break to the Debugger and print the assertion then execute the
  345.     statement. If DEBUGON or DEBUGFULL are not defined then check_action does nothing.
  346.  
  347. **************************************************************************************/
  348.  
  349. #if DEBUGLEVEL==DEBUGON
  350.  
  351. #define check_action(assertion, action)                                    \
  352.     if (true) {                                                            \
  353.         if (assertion) ;                                                \
  354.         else {                                                            \
  355.             dprintf(notrace, "Assertion \"%s\" Failed",    #assertion);    \
  356.             { action }                                                    \
  357.         }                                                                \
  358.     } else PlaceHolder()
  359.  
  360. #elif DEBUGLEVEL==DEBUGFULL
  361.  
  362. #define check_action(assertion, action)                                    \
  363.     if (true) {                                                            \
  364.         if (assertion) ;                                                \
  365.         else {                                                            \
  366.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  367.                                 "File: %s\n"                            \
  368.                                 "Line: %d",                                \
  369.                 #assertion, __FILE__, __LINE__);                        \
  370.             { action }                                                    \
  371.         }                                                                \
  372.     } else PlaceHolder()
  373.  
  374. #else
  375.  
  376. #define check_action(assertion, action)
  377.  
  378. #endif
  379.  
  380. /*<FF>*/
  381. /**************************************************************************************
  382.  
  383. MACRO
  384.     ncheck_action
  385.  
  386. DESCRIPTION
  387.     If DEBUGON or DEBUGFULL are defined then check_action will evaluate the assertion
  388.     and if it evaluates to non-zero break to the Debugger and print the assertion then
  389.     execute the statement. If DEBUGON or DEBUGFULL are not defined then ncheck_action
  390.     does nothing.
  391.  
  392. **************************************************************************************/
  393.  
  394. #if    DEBUGLEVEL==DEBUGON
  395.  
  396. #define ncheck_action(assertion, action)                                            \
  397.     if (true) {                                                                        \
  398.         void*    __privateAssertion    = (void*)(assertion);                            \
  399.                                                                                     \
  400.         if (__privateAssertion) {                                                    \
  401.             dprintf(notrace, "Assertion \"!(%s [= 0x%08X])\" Failed",                \
  402.                 #assertion, __privateAssertion);                                    \
  403.             { action }                                                                \
  404.         }                                                                            \
  405.     } else PlaceHolder()
  406.  
  407. #elif DEBUGLEVEL==DEBUGFULL
  408.  
  409. #define ncheck_action(assertion, action)                                            \
  410.     if (true) {                                                                        \
  411.         void*    __privateAssertion    = (void*)(assertion);                            \
  412.                                                                                     \
  413.         if (__privateAssertion) {                                                    \
  414.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  415.                                 "File: %s\n"                                        \
  416.                                 "Line: %d",                                            \
  417.             #assertion, __privateAssertion, __FILE__, __LINE__);                    \
  418.             { action }                                                                \
  419.         }                                                                            \
  420.     } else PlaceHolder()
  421.  
  422. #else
  423.  
  424. #define ncheck_action(assertion, action)
  425.  
  426. #endif
  427.  
  428. /*<FF>*/
  429. /**************************************************************************************
  430.  
  431. MACRO
  432.     require
  433.  
  434. DESCRIPTION
  435.     require tests the assertion just as check does (with a break into the Debugger if
  436.     the assertion failed and DEBUGON or DEBUGFULL was defined). If the assertion fails
  437.     then a goto exception is executed.
  438.  
  439. EXAMPLE
  440.     OSErr DoStuff(void)
  441.     {
  442.         FooTypeHandle        hFoo;
  443.         BananaTypeHandle    hBanana;
  444.         
  445.         hFoo = NewHandle(sizeof(FooType));
  446.         require(hFoo, NewHandle_hFoo);
  447.         
  448.         hBanana = NewHandle(&hBanana, sizeof(BananaType));
  449.         require(hBanana, NewHandle_hBanana);
  450.         
  451.         return(noErr);
  452.         
  453.     NewHandle_hBanana:
  454.         DisposHandle(hFoo);
  455.     NewHandle_hFoo:
  456.         return(memFullErr);
  457.     }
  458.  
  459. **************************************************************************************/
  460.  
  461. #if DEBUGLEVEL==DEBUGON
  462.  
  463. #define require(assertion, exception)                                    \
  464.     if (true) {                                                            \
  465.         if (assertion) ;                                                \
  466.         else {                                                            \
  467.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  468.                                 "Exception \"%s\" Raised",                \
  469.             #assertion, #exception);                                    \
  470.             goto exception;                                                \
  471.             resumeLabel(exception);                                        \
  472.         }                                                                \
  473.     } else PlaceHolder()
  474.  
  475. #elif DEBUGLEVEL==DEBUGFULL
  476.  
  477. #define require(assertion, exception)                                    \
  478.     if (true) {                                                            \
  479.         if (assertion) ;                                                \
  480.         else {                                                            \
  481.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  482.                                 "Exception \"%s\" Raised\n"                \
  483.                                 "File: %s\n"                            \
  484.                                 "Line: %d",                                \
  485.                 #assertion, #exception, __FILE__, __LINE__);            \
  486.             goto exception;                                                \
  487.             resumeLabel(exception);                                        \
  488.         }                                                                \
  489.     } else PlaceHolder()
  490.  
  491. #else
  492.  
  493. #define require(assertion, exception)                                    \
  494.     if (true) {                                                            \
  495.         if (assertion) ;                                                \
  496.         else {                                                            \
  497.             goto exception;                                                \
  498.             resumeLabel(exception);                                        \
  499.         }                                                                \
  500.     } else PlaceHolder()
  501.  
  502. #endif
  503.  
  504. /*<FF>*/
  505. /**************************************************************************************
  506.  
  507. MACRO
  508.     nrequire
  509.  
  510. DESCRIPTION
  511.     nrequire is the same as require except that it insures that assertion is false.
  512.  
  513. EXAMPLE
  514.     OSErr DoStuff(void)
  515.     {
  516.         OSErr                theError;
  517.         FooTypeHandle        hFoo;
  518.         BananaTypeHandle    hBanana;
  519.         
  520.         theError = MNewHandle(&hFoo, sizeof(FooType));
  521.         nrequire(theError, MNewHandle_hFoo);
  522.         
  523.         theError = MNewHandle(&hBanana, sizeof(BananaType));
  524.         nrequire(theError, MNewHandle_hBanana);
  525.         
  526.         return(noErr);
  527.         
  528.     MNewHandle_hBanana:
  529.         (void)MDisposHandle(&hFoo);
  530.     MNewHandle_hFoo:
  531.         return(theError);
  532.     }
  533.  
  534. **************************************************************************************/
  535.  
  536. #if DEBUGLEVEL==DEBUGON
  537.  
  538. #define nrequire(assertion, exception)                                                \
  539.     if (true) {                                                                        \
  540.         void*    __privateAssertion    = (void*)(assertion);                            \
  541.                                                                                     \
  542.         if (__privateAssertion) {                                                    \
  543.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  544.                                 "Exception \"%s\" Raised",                            \
  545.                 #assertion, __privateAssertion, #exception);                        \
  546.             goto exception;                                                            \
  547.             resumeLabel(exception);                                                    \
  548.         }                                                                            \
  549.     } else PlaceHolder()
  550.  
  551. #elif DEBUGLEVEL==DEBUGFULL
  552.  
  553. #define nrequire(assertion, exception)                                                \
  554.     if (true) {                                                                        \
  555.         void*    __privateAssertion    = (void*)(assertion);                            \
  556.                                                                                     \
  557.         if (__privateAssertion) {                                                    \
  558.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  559.                                 "Exception \"%s\" Raised\n"                            \
  560.                                 "File: %s\n"                                        \
  561.                                 "Line: %d",                                            \
  562.                 #assertion, __privateAssertion, #exception, __FILE__,                \
  563.                 __LINE__);                                                            \
  564.             goto exception;                                                            \
  565.             resumeLabel(exception);                                                    \
  566.         }                                                                            \
  567.     } else PlaceHolder()
  568.  
  569. #else
  570.  
  571. #define nrequire(assertion, exception)                                                \
  572.     if (true) {                                                                        \
  573.         if (assertion) {                                                            \
  574.             goto exception;                                                            \
  575.             resumeLabel(exception);                                                    \
  576.         }                                                                            \
  577.     } else PlaceHolder()
  578.  
  579. #endif
  580.  
  581. /*<FF>*/
  582. /**************************************************************************************
  583.  
  584. MACRO
  585.     require_action
  586.  
  587. DESCRIPTION
  588.     require_action is identical to require except if the assertion fails then action
  589.     is executed.
  590.  
  591. EXAMPLE
  592.     OSErr DoStuff(void)
  593.     {
  594.         FooTypeHandle        hFoo;
  595.         BananaTypeHandle    hBanana;
  596.         OSErr                theError;
  597.         
  598.         hFoo = NewHandle(sizeof(FooType));
  599.         require_action(hFoo, NewHandle_hFoo, theError = MemError(););
  600.         
  601.         hBanana = NewHandle(&hBanana, sizeof(BananaType));
  602.         require_action(hBanana, NewHandle_hBanana, theError = MemError(););
  603.         
  604.         return(noErr);
  605.         
  606.     NewHandle_hBanana:
  607.         DisposHandle(hFoo);
  608.     NewHandle_hFoo:
  609.         return(theError);
  610.     }
  611.  
  612. **************************************************************************************/
  613.  
  614. #if DEBUGLEVEL==DEBUGON
  615.  
  616. #define require_action(assertion, exception, action)                    \
  617.     if (true) {                                                            \
  618.         if (assertion) ;                                                \
  619.         else {                                                            \
  620.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  621.                                 "Exception \"%s\" Raised",                \
  622.             #assertion, #exception);                                    \
  623.             { action }                                                    \
  624.             goto exception;                                                \
  625.             resumeLabel(exception);                                        \
  626.         }                                                                \
  627.     } else PlaceHolder()
  628.  
  629. #elif DEBUGLEVEL==DEBUGFULL
  630.  
  631. #define require_action(assertion, exception, action)                    \
  632.     if (true) {                                                            \
  633.         if (assertion) ;                                                \
  634.         else {                                                            \
  635.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  636.                                 "Exception \"%s\" Raised\n"                \
  637.                                 "File: %s\n"                            \
  638.                                 "Line: %d",                                \
  639.                 #assertion, #exception, __FILE__, __LINE__);            \
  640.             { action }                                                    \
  641.             goto exception;                                                \
  642.             resumeLabel(exception);                                        \
  643.         }                                                                \
  644.     } else PlaceHolder()
  645.  
  646. #else
  647.  
  648. #define require_action(assertion, exception, action)                    \
  649.     if (true) {                                                            \
  650.         if (assertion) ;                                                \
  651.         else {                                                            \
  652.             { action }                                                    \
  653.             goto exception;                                                \
  654.             resumeLabel(exception);                                        \
  655.         }                                                                \
  656.     } else PlaceHolder()
  657.  
  658. #endif
  659.  
  660. /*<FF>*/
  661. /**************************************************************************************
  662.  
  663. MACRO
  664.     nrequire_action
  665.  
  666. DESCRIPTION
  667.     nrequire_action is the same as nrequire except it executes action when the
  668.     assertion is true.
  669.  
  670. EXAMPLE
  671.     void *DoStuff(void)
  672.     {
  673.         OSErr                theError;
  674.         FooTypeHandle        hFoo;
  675.         BananaTypeHandle    hBanana;
  676.         void *                result;
  677.         
  678.         theError = GetSpecialHandle(&hFoo);
  679.         nrequire_action(theError, GetSpecialHandle, result = nil);
  680.         
  681.         result = (*hFoo)->theStuff;
  682.         
  683.         // Just let if fall through in this contrived example
  684.         
  685. GetSpecialHandle:
  686.         return(result);
  687.     }
  688.  
  689. **************************************************************************************/
  690.  
  691. #if DEBUGLEVEL==DEBUGON
  692.  
  693. #define nrequire_action(assertion, exception, action)                                \
  694.     if (true) {                                                                        \
  695.         void*    __privateAssertion    = (void*)(assertion);                            \
  696.                                                                                     \
  697.         if (__privateAssertion) {                                                    \
  698.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  699.                                 "Exception \"%s\" Raised",                            \
  700.                 #assertion, __privateAssertion, #exception);                        \
  701.             { action }                                                                \
  702.             goto exception;                                                            \
  703.             resumeLabel(exception);                                                    \
  704.         }                                                                            \
  705.     } else PlaceHolder()
  706.  
  707. #elif DEBUGLEVEL==DEBUGFULL
  708.  
  709. #define nrequire_action(assertion, exception, action)                                \
  710.     if (true) {                                                                        \
  711.         void*    __privateAssertion    = (void*)(assertion);                            \
  712.                                                                                     \
  713.         if (__privateAssertion) {                                                    \
  714.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  715.                                 "Exception \"%s\" Raised\n"                            \
  716.                                 "File: %s\n"                                        \
  717.                                 "Line: %d",                                            \
  718.                 #assertion, __privateAssertion, #exception, __FILE__,                \
  719.                 __LINE__);                                                            \
  720.             { action }                                                                \
  721.             goto exception;                                                            \
  722.             resumeLabel(exception);                                                    \
  723.         }                                                                            \
  724.     } else PlaceHolder()
  725.  
  726. #else
  727.  
  728. #define nrequire_action(assertion, exception, action)                    \
  729.     if (true) {                                                            \
  730.         if (assertion) {                                                \
  731.             { action }                                                    \
  732.             goto exception;                                                \
  733.             resumeLabel(exception);                                        \
  734.         }                                                                \
  735.     } else PlaceHolder()
  736.  
  737. #endif
  738.  
  739. /*<FF>*/
  740. /**************************************************************************************
  741.  
  742. MACRO
  743.     retry
  744.  
  745. DESCRIPTION
  746.     retry is used to start a routine over if the routine fails. Variable initialization
  747.     is not redone so variables can be changed to retry the routine under different
  748.     circumstances. Routine parameters should not be changed or the routine will no
  749.     longer be fulfilling its contract.
  750.  
  751. EXAMPLE
  752.     OSErr DoStuff(void)
  753.     {
  754.         OSErr                theError;
  755.         Handle                h;
  756.         Int16                iSize;
  757.         Int16                iPieces = kGoodNumber;
  758.         Int16                i;
  759.         
  760.     start:
  761.     
  762.         iSize = kFullSize / iPieces;
  763.         
  764.         for (i = 0; i <= iPieces; i++) {
  765.             theError = MNewHandle(&h, iSize);
  766.             nrequire(theError, MNewHandle);
  767.             .
  768.             .
  769.             .
  770.             theError = MDisposeHandle(&h);
  771.             ncheck(theError);
  772.         }
  773.         
  774.         return(noErr);
  775.                 
  776.     MNewHandle:
  777.  
  778.         (void)MDisposeHandle(&h);
  779.         iPieces += kMore;
  780.         
  781.         if (iPieces < kMaxPieces)
  782.             retry;
  783.         else
  784.             return(theError);
  785.     }
  786.  
  787. **************************************************************************************/
  788.  
  789. #define retry                                 \
  790.     if (true) {                                \
  791.         goto start;                            \
  792.     } else PlaceHolder()
  793.     
  794.     
  795. /*<FF>*/
  796. /**************************************************************************************
  797.  
  798. MACRO
  799.     resume
  800.  
  801. DESCRIPTION
  802.     resume is used to resume execution at the point where an exception occured. Below
  803.     is a very contrived example of it's use. Note that this example also shows how
  804.     to handle an exception in an exception. Although this is rarly neccisary sometimes
  805.     it can be useful but make sure that it is clearly commented.
  806.  
  807. EXAMPLE
  808.     Boolean DoStuff(Boolean ***theSettings)
  809.     {
  810.         *theSettings = (Boolean **)GetResource('STIN', 128);
  811.         require(*theSettings, GetResource);
  812.         
  813.         // Execution will resume here
  814.         
  815.         return(***theSettings);
  816.     
  817.     GetResource:
  818.         *theSettings = (Boolean **)NewHandle(sizeof(Boolean));
  819.         require(*theSettings, NewHandle);
  820.         *theSettings = false;
  821.         resume(GetResource);
  822.         
  823.     // Secondary exceptions
  824.         
  825.     NewHandle:
  826.         return(false);
  827.     }
  828.  
  829. **************************************************************************************/
  830.  
  831.  
  832. #define resume(exception)                    \
  833.     if (true) {                                \
  834.         goto resume_ ## exception;            \
  835.     } else PlaceHolder()
  836.  
  837.  
  838. /*<FF>*/
  839. /*************************************************************************************/
  840.  
  841. #endif